

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/blog/img/fluid.png">
  <link rel="icon" href="/blog/images/base.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Airfe">
  <meta name="keywords" content="">
  
    <meta name="description" content="本文将介绍Node.js的基本使用。">
<meta property="og:type" content="article">
<meta property="og:title" content="Node.js">
<meta property="og:url" content="https://airfe.gitee.io/blog/2023/04/01/Node.js/index.html">
<meta property="og:site_name" content="Airfe的博客">
<meta property="og:description" content="本文将介绍Node.js的基本使用。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/pageImage/nodejs.png">
<meta property="article:published_time" content="2023-04-01T00:00:00.000Z">
<meta property="article:modified_time" content="2024-02-26T12:22:18.301Z">
<meta property="article:author" content="Airfe">
<meta property="article:tag" content="服务器">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/pageImage/nodejs.png">
  
  
  
    <meta name="referrer" content="no-referrer" />
  
  <title>Node.js - Airfe的博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/blog/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/blog/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/blog/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"airfe.gitee.io","root":"/blog/","version":"1.9.4","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":"699a5d71ac7179b23874a59b0666a6f6","google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","app_key":"P5fzMTGSJIoTaGvmgzsUHeNZ","server_url":"https://rw68dmke.lc-cn-n1-shared.com","path":"window.location.pathname","ignore_local":false}},"search_path":"/blog/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/blog/js/utils.js" ></script>
  <script  src="/blog/js/color-schema.js" ></script>
  

  
    <!-- Baidu Analytics -->
    <script async>
      if (!Fluid.ctx.dnt) {
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?699a5d71ac7179b23874a59b0666a6f6";
          var s = document.getElementsByTagName("script")[0];
          s.parentNode.insertBefore(hm, s);
        })();
      }
    </script>
  

  

  

  

  

  

  
    
  



  
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/blog/">
      <strong>Airfe</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/categories/">
                <i class="iconfont icon-category-fill"></i>
                <span>分类</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/tags/">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/about/">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/links/">
                <i class="iconfont icon-link-fill"></i>
                <span>友链</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/blog/images/bg.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="Node.js"></span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2023-04-01 08:00" pubdate>
          2023年04月01日
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          21k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          173 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Node.js</h1>
            
            
              <div class="markdown-body">
                
                <h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1.简介"></a>1.简介</h2><p>官网：<a target="_blank" rel="noopener" href="https://nodejs.org/zh-cn/">https://nodejs.org/zh-cn/</a></p>
<p>理解node是一个运行环境：</p>
<ul>
<li>浏览器是 JavaScript 的前端运行环境</li>
<li>Node.js 是 JavaScript 的后端运行环境</li>
<li>Node.js 中无法调用 DOM 和 BOM 等浏览器内置 API</li>
</ul>
<h2 id="2-fs文件系统模块"><a href="#2-fs文件系统模块" class="headerlink" title="2.fs文件系统模块"></a>2.fs文件系统模块</h2><p> 导入fs</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">&quot;fs&quot;</span>)<br></code></pre></td></tr></table></figure>

<p>方法（必选参数）[可选参数]</p>
<p>读取指定文件中的内容：<code>fs.readFile(path[, option], callback)</code></p>
<ul>
<li>path：必选参数，字符串，表示文件的路径</li>
<li>options：可选参数，表示以什么编码格式来读取文件，比如utf8 </li>
<li>callback：必选参数，文件读取完成后，通过回调函数拿到读取结果，function(err,dataStr){ }，如果读取成功，err为null</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 1. 导入 fs 模块，来操作文件</span><br><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;fs&#x27;</span>)<br><br><span class="hljs-comment">// 2. 调用 fs.readFile() 方法读取文件</span><br>fs.<span class="hljs-title function_">readFile</span>(<span class="hljs-string">&#x27;./files/11.txt&#x27;</span>, <span class="hljs-string">&#x27;utf8&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">err, dataStr</span>) &#123;<br>  <span class="hljs-keyword">if</span> (err) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;读取文件失败！&#x27;</span> + err.<span class="hljs-property">message</span>)<br>  &#125;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;读取文件成功！&#x27;</span> + dataStr)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p>向指定的文件中写入内容：<code>fs.writeFile(path, data[, option], callback)</code></p>
<ul>
<li>path：必选参数，字符串，文件路径</li>
<li>data：必选参数，写入的内容</li>
<li>options：可选参数，设置字符集，默认值是 utf8</li>
<li>callback：必选参数，件写入完成后的回调函数</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;fs&#x27;</span>)<br><br><span class="hljs-comment">// 调用 fs.writeFile() 方法，写入文件的内容</span><br>fs.<span class="hljs-title function_">writeFile</span>(<span class="hljs-string">&#x27;./files/3.txt&#x27;</span>, <span class="hljs-string">&#x27;ok123&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>) &#123;<br>  <span class="hljs-keyword">if</span> (err) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;文件写入失败！&#x27;</span> + err.<span class="hljs-property">message</span>)<br>  &#125;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;文件写入成功！&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure>

<blockquote>
<p>tip：<strong>写入会覆盖原内容</strong>，fs.writeFile()只能用来创建文件，不能创建路径</p>
</blockquote>
<h3 id="考试成绩整理案例"><a href="#考试成绩整理案例" class="headerlink" title="考试成绩整理案例"></a>考试成绩整理案例</h3><p>要求：使用fs文件系统模块，将素材目录下成绩.txt文件中的数据，整理到成绩-ok.txt文件中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 1. 导入 fs 模块</span><br><span class="hljs-type">const</span> <span class="hljs-variable">fs</span> <span class="hljs-operator">=</span> require(<span class="hljs-string">&#x27;fs&#x27;</span>)<br><span class="hljs-comment">// 2. 调用fs.readFile()读取文件的内容</span><br>fs.readFile(<span class="hljs-string">&#x27;../素材/成绩.txt&#x27;</span>,<span class="hljs-string">&#x27;utf8&#x27;</span>,function(err,dataStr)&#123;<br>    <span class="hljs-comment">//3. 判断是否读取成功</span><br>    <span class="hljs-keyword">if</span>(err)&#123;<br>        <span class="hljs-keyword">return</span> console.log(<span class="hljs-string">&#x27;读取文件失败！&#x27;</span>+ err.message)<br>    &#125;<br>   <span class="hljs-comment">//4.处理读出来的数据</span><br>    <span class="hljs-type">const</span> <span class="hljs-variable">arrOld</span> <span class="hljs-operator">=</span> dataStr.split(<span class="hljs-string">&#x27; &#x27;</span>)<br>    <span class="hljs-type">const</span> <span class="hljs-variable">arrNew</span> <span class="hljs-operator">=</span> [] <br>    arrOld.forEach(item =&gt; &#123;<br>        arrNew,push(item.replace(<span class="hljs-string">&#x27;=&#x27;</span>,<span class="hljs-string">&#x27;:&#x27;</span>))<br>    &#125;)<br>    <span class="hljs-type">const</span> <span class="hljs-variable">newStr</span> <span class="hljs-operator">=</span> arrNew.join(<span class="hljs-string">&#x27;\r\n&#x27;</span>)<br>    console.log(newStr)<br>&#125;)<br></code></pre></td></tr></table></figure>

<h3 id="路径动态拼接的问题"><a href="#路径动态拼接的问题" class="headerlink" title="路径动态拼接的问题"></a>路径动态拼接的问题</h3><p>如果提供的操作路径是以.&#x2F;或…&#x2F;开头的<strong>相对路径</strong>时，很容易出现路径动态拼接错误的问题。</p>
<p>原因：代码在运行的时候，<strong>会以执行node命令时所处的目录</strong>，动态拼接出被操作文件的完整路径。</p>
<p><img src="" srcset="/blog/img/loading.gif" lazyload data-original="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/%20markdown/image-20230427221555559.png" alt="image-20230427221555559"></p>
<p>解决方法：不用相对路径。1.可以从盘符开始（可移植性差），2.<strong>__dirname</strong> 表示当前文件所处的目录</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript">fs.<span class="hljs-title function_">readFile</span>(__dirname + <span class="hljs-string">&#x27;/files/1.txt&#x27;</span>, <span class="hljs-string">&#x27;utf8&#x27;</span>, <span class="hljs-keyword">function</span>(<span class="hljs-params">err, dataStr</span>) &#123;<br>  <span class="hljs-keyword">if</span> (err) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;读取文件失败！&#x27;</span> + err.<span class="hljs-property">message</span>)<br>  &#125;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;读取文件成功！&#x27;</span> + dataStr)<br>&#125;)<br></code></pre></td></tr></table></figure>

<h2 id="3-path路径模块"><a href="#3-path路径模块" class="headerlink" title="3.path路径模块"></a>3.path路径模块</h2><p>导入path</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&quot;path&quot;</span>)<br></code></pre></td></tr></table></figure>

<p>方法</p>
<p>路径拼接：<code>path.join(...paths)</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 注意：  ../ 会抵消前面的路径</span><br><span class="hljs-keyword">const</span> pathStr = path.<span class="hljs-title function_">join</span>(<span class="hljs-string">&#x27;/a&#x27;</span>, <span class="hljs-string">&#x27;/b/c&#x27;</span>, <span class="hljs-string">&#x27;../&#x27;</span>, <span class="hljs-string">&#x27;./d&#x27;</span>, <span class="hljs-string">&#x27;e&#x27;</span>)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(pathStr)  <span class="hljs-comment">// \a\b\d\e</span><br></code></pre></td></tr></table></figure>

<p>获取路径中的最后一部分：<code>path.basename(path[, ext])</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;path&#x27;</span>)<br><br><span class="hljs-comment">// 定义文件的存放路径</span><br><span class="hljs-keyword">const</span> fpath = <span class="hljs-string">&#x27;/a/b/c/index.html&#x27;</span><br><span class="hljs-keyword">const</span> fullName = path.<span class="hljs-title function_">basename</span>(fpath)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(fullName) <span class="hljs-comment">// index.html</span><br><span class="hljs-comment">// 去除文件扩展名</span><br><span class="hljs-keyword">const</span> nameWithoutExt = path.<span class="hljs-title function_">basename</span>(fpath, <span class="hljs-string">&#x27;.html&#x27;</span>)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(nameWithoutExt) <span class="hljs-comment">// index</span><br></code></pre></td></tr></table></figure>

<p>获取路径中的文件扩展名：<code>path.extname(path)</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;path&#x27;</span>)<br><br><span class="hljs-comment">// 这是文件的存放路径</span><br><span class="hljs-keyword">const</span> fpath = <span class="hljs-string">&#x27;/a/b/c/index.html&#x27;</span><br><span class="hljs-keyword">const</span> fext = path.<span class="hljs-title function_">extname</span>(fpath)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(fext)<span class="hljs-comment">//输出.html</span><br></code></pre></td></tr></table></figure>

<h2 id="4-http模块"><a href="#4-http模块" class="headerlink" title="4.http模块"></a>4.http模块</h2><p> http 模块是 Node.js 官方提供的用来创建 web 服务器的模块</p>
<p>导入http</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">&quot;http&quot;</span>)<br></code></pre></td></tr></table></figure>

<p>创建web服务器： <code>http.createServer()</code> </p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 1. 导入 http 模块</span><br><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;http&#x27;</span>)<br><br><span class="hljs-comment">// 2. 创建 web 服务器实例</span><br><span class="hljs-keyword">const</span> server = http.<span class="hljs-title function_">createServer</span>()<br><br><span class="hljs-comment">// 3. 为服务器实例绑定 request 事件，监听客户端的请求</span><br>server.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;request&#x27;</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Someone visit our web server.&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 4. 启动服务器</span><br>server.<span class="hljs-title function_">listen</span>(<span class="hljs-number">8080</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;  <br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;server running at http://127.0.0.1:8080&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p>req包含了与客户端相关的数据和属性，比如req.url req.method; </p>
<p>res包含了与服务器相关的数据和属性，比如res.end()响应内容</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript">server.<span class="hljs-title function_">on</span>(<span class="hljs-string">&#x27;request&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// req.url 是客户端请求的 URL 地址</span><br>  <span class="hljs-keyword">const</span> url = req.<span class="hljs-property">url</span><br>  <span class="hljs-comment">// req.method 是客户端请求的 method 类型</span><br>  <span class="hljs-keyword">const</span> method = req.<span class="hljs-property">method</span><br>  <span class="hljs-keyword">const</span> str = <span class="hljs-string">`Your request url is <span class="hljs-subst">$&#123;url&#125;</span>, and request method is <span class="hljs-subst">$&#123;method&#125;</span>`</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(str)<br>  <br>  <span class="hljs-comment">// 调用 res.end() 方法，向客户端响应一些内容</span><br>  res.<span class="hljs-title function_">end</span>(str)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p>当调用 res.end() 方法，向客户端发送中文内容的时候，会出现乱码问题，此时，需要手动设置内容的编码格式，</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 调用 res.setHeader() 方法，设置 Content-Type 响应头，解决中文乱码的问题</span><br> res.<span class="hljs-title function_">setHeader</span>(<span class="hljs-string">&#x27;Content-Type&#x27;</span>, <span class="hljs-string">&#x27;text/html; charset=utf-8&#x27;</span>)<br></code></pre></td></tr></table></figure>

<h2 id="5-模块化概念"><a href="#5-模块化概念" class="headerlink" title="5.模块化概念"></a>5.模块化概念</h2><figure class="highlight plaintext"><figcaption><span>规定</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs Node.js```遵循了``CommonJS``模块化规范，CommonJS"><br>- 每个模块内部，module 变量代表当前模块<br>- module 变量是一个对象，它的 exports 属性（即 module.exports）是对外的接口<br>- 加载某个模块，其实是加载该模块的 module.exports 属性。require() 方法用于加载模块<br><br>分类：<br><br>- **内置模块**（内置模块是由 Node.j s 官方提供的，例如 fs、path、http 等）<br><br>- **自定义模块**（用户创建的每个 .js 文件，都是自定义模块）<br><br>- **第三方模块**（由第三方开发出来的模块，使用前需要先下载）<br><br>  ```js<br>  const fs = require(&#x27;fs&#x27;)							// 内置模块<br>  const custom = require(&#x27;./custom.js&#x27;)	// 自定义模块，需指明路径，可以省略 .js 的后缀名<br>  const moment = require(&#x27;moment&#x27;)			// 第三方模块<br></code></pre></td></tr></table></figure>

<blockquote>
<p>tip：使用 require() 方法加载其它模块时，会<strong>执行</strong>被加载模块中的代码</p>
</blockquote>
<p>模块作用域：</p>
<p>在自定义模块中定义的<strong>变量、方法</strong>等成员，只能在当前模块内被访问。好处是防止了全局变量污染的问题</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 模块作用域</span><br><span class="hljs-keyword">const</span> username = <span class="hljs-string">&#x27;张三&#x27;</span><br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;大家好，我是&#x27;</span> + username)<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> custom = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./模块作用域&#x27;</span>)<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(custom) <span class="hljs-comment">//输出为&#123;&#125;</span><br></code></pre></td></tr></table></figure>

<p>向外共享模块作用域中的成员方式：</p>
<ol>
<li><p><code>module</code>对象</p>
<p>在每个.js自定义模块中都有一个moudle对象，它存储了和当前模块有关的信息</p>
<ul>
<li>可以使用<code>module.exports</code>对象，将模块内的成员共享出去</li>
<li>外界用<code>require()</code>方法导入，得到的就是 <code>module.exports</code> 所指向的对象，默认该属性是<code>&#123;&#125;</code></li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 在一个自定义模块中，默认情况下， module.exports = &#123;&#125;</span><br><span class="hljs-keyword">const</span> age = <span class="hljs-number">20</span><br><br><span class="hljs-comment">// 向 module.exports 对象上挂载 username 属性</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">username</span> = <span class="hljs-string">&#x27;zs&#x27;</span><br><span class="hljs-comment">// 向 module.exports 对象上挂载 sayHello 方法</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">sayHello</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Hello!&#x27;</span>)<br>&#125;<br><br><span class="hljs-comment">// 让 module.exports 指向一个全新的对象</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = &#123;<br>  <span class="hljs-attr">nickname</span>: <span class="hljs-string">&#x27;小黑&#x27;</span>,<br>  <span class="hljs-title function_">sayHi</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Hi!&#x27;</span>)<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<blockquote>
<p>require（）得到的是这个全新的对象</p>
</blockquote>
<ol start="2">
<li><p><code>export</code>对象</p>
<p>默认情况下，exports 和 module.exports 指向同一个对象。最终共享的结果，还是以 module.exports 指向的对象为准。 </p>
</li>
<li><p>联系</p>
<p>只是在刚开始<code>export</code>和<code>module.export</code>共享数据，本来都为{}，其中一个有了指向对象另外的也有了，之后的改变便<strong>不同步</strong>了。</p>
<blockquote>
<p>不建议同时使用</p>
</blockquote>
</li>
</ol>
<h2 id="6-npm与包"><a href="#6-npm与包" class="headerlink" title="6.npm与包"></a>6.npm与包</h2><p>Node.js 中的第三方模块又叫做<strong>包</strong></p>
<p>npm是包管理工具</p>
<h3 id="安装包后多了哪些文件"><a href="#安装包后多了哪些文件" class="headerlink" title="安装包后多了哪些文件"></a>安装包后多了哪些文件</h3><p>**node_modules **</p>
<p>用来存放所有已安装到项目中的包。require() 导入第三方包时，从这个目录中查找并加载</p>
<p><strong>package-lock.json</strong></p>
<p>记录 node_modules 目录下的每一个包的下载信息，例如包的名字、版本号、下载地址等</p>
<h3 id="安装指定版本的包"><a href="#安装指定版本的包" class="headerlink" title="安装指定版本的包"></a>安装指定版本的包</h3><p>npm install 命令默认安装最新版本的包。如需安装指定版本的包，在包名之后，@</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Git">npm i 包的完整名称@版本号<br></code></pre></td></tr></table></figure>

<h3 id="版本号"><a href="#版本号" class="headerlink" title="版本号"></a>版本号</h3><p>包的版本号以“点分十进制”形式进行定义，总共有三位数字，如 2.24.0。其中每一位数字所代表的的含义如下</p>
<ul>
<li>第1位数字：<strong>大版本</strong></li>
<li>第2位数字：<strong>功能版本</strong></li>
<li>第3位数字：<strong>Bug修复版本</strong></li>
</ul>
<p>版本号提升的规则：只要前面的版本号增长了，则后面的版本号归零</p>
<h3 id="多人协作的问题"><a href="#多人协作的问题" class="headerlink" title="多人协作的问题"></a>多人协作的问题</h3><p><strong>package.json</strong></p>
<p>第三方包的体积过大，不方便团队成员之间共享项目源代码。</p>
<p>故要把 node_modules文件夹，添加到 .gitignore 忽略文件中。</p>
<p><code>package.json</code> <strong>记录项目中安装了哪些包</strong>，<code>npm init -y</code>快速创建<code>package.json</code>这个包管理配置文件。</p>
<p>执行npm install 命令时，npm 包管理工具会先读取package. json中的dependencies 节点，读取到记录的所有依赖包名称和版本号之后，npm包管理工具会把这些包-次性下载到项目中。</p>
<h3 id="卸载包"><a href="#卸载包" class="headerlink" title="卸载包"></a>卸载包</h3><p>运行 <code>npm uninstall</code> 命令，来卸载指定的包，没有简写形式</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs git">npm uninstall 包名<br></code></pre></td></tr></table></figure>

<h3 id="devDependencies节点"><a href="#devDependencies节点" class="headerlink" title="devDependencies节点"></a><strong>devDependencies节点</strong></h3><p>只在项目开发阶段会用到，项目上线之后不会用：记录到 <strong>devDependencies</strong>节点</p>
<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cmd">//完整写法 包名和--save-dev顺序不重要<br>npm install 包名 --save-dev     <br>或<br>//常用简写<br>npm i 包名 -D<br></code></pre></td></tr></table></figure>

<p>开发和项目上线之后都需要用到：记录到 **dependencies **节点</p>
<h3 id="i5ting-toc"><a href="#i5ting-toc" class="headerlink" title="i5ting_toc"></a>i5ting_toc</h3><p>i5ting_toc 是一个可以把 md 文档转为 html 页面的小工具</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs git">npm i i5ting_toc -g						# 安装<br>i5ting_toc -f sample.md -o		# 在sample.md目录下转换<br></code></pre></td></tr></table></figure>

<h2 id="7-开发属于自己的包"><a href="#7-开发属于自己的包" class="headerlink" title="7.开发属于自己的包"></a>7.开发属于自己的包</h2><h3 id="规范的包结构"><a href="#规范的包结构" class="headerlink" title="规范的包结构"></a>规范的包结构</h3><p>组成结构，必须符合以下 3 点要求</p>
<ul>
<li>包必须以单独的目录而存在</li>
<li>包的顶级目录（点进去的目录）下要必须包含 package.json 这个包管理配置文件</li>
<li>package.json 中必须包含 name，version，main这三个属性，分别代表包的名字、版本号、包的入口(.js文件)（require()加载的文件）</li>
</ul>
<blockquote>
<p>name不能和已有的重复，和文件夹名字无关。main表示入口文件。</p>
</blockquote>
<p>包的入口文件</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// src 文件夹下开发代码，导入到 index.js 中</span><br><span class="hljs-keyword">const</span> date = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./src/dateFormat&#x27;</span>)<br><span class="hljs-keyword">const</span> <span class="hljs-built_in">escape</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./src/htmlEscape&#x27;</span>)<br><br><span class="hljs-comment">// 向外暴露需要的成员</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = &#123;<br>  ...date,		<span class="hljs-comment">// ... 展开运算符，将data所有属性交给新对象</span><br>  ...<span class="hljs-built_in">escape</span>		<span class="hljs-comment">// ... 展开运算符，将escape所有属性交给新对象</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="发布包"><a href="#发布包" class="headerlink" title="发布包"></a>发布包</h3><ul>
<li><a target="_blank" rel="noopener" href="https://www.npmjs.com/">https://www.npmjs.com/</a> 注册 npm 账号，终端中执行 npm login 命令，依次输入用户名、密码、邮箱后，即可登录成功</li>
</ul>
<p> 注意：执行命令前，必须先把下包的服务器地址切换为 npm 的官方服务器。否则会导致发布包失败！先用nrm命令检查一下，nrm use 命令切换。终端切换到包的根目录之后，运行 npm publish 命令，即可将包发布到 npm 上（注意：包名不能雷同）</p>
<p>运行 npm unpublish 包名 –force命令，即可从 npm 删除已发布的包</p>
<ul>
<li>npm unpublish 命令只能删除 72 小时以内发布的包</li>
<li>npm unpublish 删除的包，在 24 小时内不允许重复发布</li>
<li>发布包的时候要慎重，尽量不要往 npm 上发布没有意义的包</li>
</ul>
<h2 id="8-模块的加载机制"><a href="#8-模块的加载机制" class="headerlink" title="8.模块的加载机制"></a>8.模块的加载机制</h2><p>模块在第一次加载后（第一次<strong>require()后</strong>）会被缓存。也就是说多次调用 <strong>require()</strong> 模块的代码只会被执行一次。</p>
<p>不论是内置模块、用户自定义模块、还是第三方模块，它们都会优先从缓存中加载，从而提高模块的加载效率。</p>
<p>内置模块的加载机制</p>
<ul>
<li>内置模块的加载优先级最高（当第三方模块和内置模块同名时）</li>
</ul>
<p>自定义模块的加载机制</p>
<ul>
<li><p>使用 require() 加载自定义模块时，必须指定以 .&#x2F; 或 …&#x2F; 开头的路径标识符。在加载自定义模块时，如果没有指定 .&#x2F; 或 …&#x2F; 这样的路径标识符，则 node 会把它当作内置模块或第三方模块进行加载。</p>
</li>
<li><p>在使用 require() 导入自定义模块时，如果省略了文件的扩展名，Node.js 会按顺序分别尝试加载以下的文件</p>
<ul>
<li>按照确切的文件名进行加载</li>
<li>补全 .js 扩展名进行加载</li>
<li>补全 .json 扩展名进行加载</li>
<li>补全 .node 扩展名进行加载</li>
<li>加载失败，终端报错</li>
</ul>
</li>
</ul>
<p>第三方模块的加载机制</p>
<ul>
<li>如果传递给 require() 的模块标识符不是一个内置模块，也没有以 .&#x2F; 或 …&#x2F; 开头，则 Node.js 会从当前模块的父目录开始，尝试从 &#x2F;node_modules 文件夹中加载第三方模块</li>
<li>如果没有找到对应的第三方模块，则移动到再上一层父目录中，进行加载，直到文件系统的根目录</li>
<li>假设在 ‘C:\Users\itheima\project\node_modules\a.js’ 里调用 require(‘tools’)，Node.js 会按以下顺序查找</li>
</ul>
<p>如果加载的是目录</p>
<ul>
<li>当把目录作为模块标识符，传递给 require() 进行加载的时候，有三种加载方式</li>
<li>在被加载的目录下查找一个叫做 package.json 的文件，并寻找 main 属性值作为 require() 加载的入口</li>
<li>如果目录里没有 package.json 文件，或者 main 入口不存在或无法解析，则 Node.js 将会试图加载目录下的 index.js 文件<br>如果以上两步都失败了，则 Node.js 会在终端打印错误消息，报告模块的缺失：Error: Cannot find module ‘xxx’</li>
</ul>
<h2 id="9-Express"><a href="#9-Express" class="headerlink" title="9.Express"></a>9.Express</h2><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>Express 是基于 Node.js 平台，快速、开放、极简的 Web 开发框架<br>通俗的理解：Express 的作用和 Node.js 内置的 http 模块类似，是专门用来创建 Web 服务器的。<br>本质就是一个 npm 上的第三方包，提供了快速创建 Web 服务器的便捷方法<br>中文官网 <a target="_blank" rel="noopener" href="http://www.expressjs.com.cn/">http://www.expressjs.com.cn/</a></p>
<blockquote>
<p>不使用 Express 能否创建 Web 服务器？<br>能，使用 Node.js 提供的原生 http 模块即可<br>有了 http 内置模块，为什么还有用 Express？<br>http 内置模块用起来很复杂，开发效率低；<br>Express 是基于内置的 http 模块进一步封装出来的，能够极大的提高开发效率<br>http 内置模块与 Express 是什么关系？<br>类似于浏览器中 Web API 和 jQuery 的关系。后者是基于前者进一步封装出来的</p>
</blockquote>
<h3 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h3><ul>
<li>在项目所处的目录中安装</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs git">npm i express<br></code></pre></td></tr></table></figure>

<ul>
<li>创建基本的 Web 服务器</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express);	// 导入express</span><br><span class="hljs-string">                        </span><br><span class="hljs-string">const app = express();							// 创建web服务器</span><br><span class="hljs-string"></span><br><span class="hljs-string">app.listen(80, () =&gt; &#123;							// 调用回调函数，listen() 启动服务器</span><br><span class="hljs-string">	console.log(&#x27;</span>express server running at <span class="hljs-attr">http</span>:<span class="hljs-comment">//127.0.0.1&#x27;)</span><br>&#125;);<br></code></pre></td></tr></table></figure>

<ul>
<li>处理请求</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 1. 导入 express</span><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 2. 创建 web 服务器</span><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">// 4. 监听客户端的 GET 和 POST 请求，并向客户端响应具体的内容</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 调用 express 提供的 res.send() 方法，向客户端响应一个  JSON 对象</span><br>  res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;zs&#x27;</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">20</span>, <span class="hljs-attr">gender</span>: <span class="hljs-string">&#x27;男&#x27;</span> &#125;)<br>&#125;)<br>app.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/user&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 调用 express 提供的 res.send() 方法，向客户端响应一个  文本字符串</span><br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;请求成功&#x27;</span>)<br>&#125;)<br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123; <br>  <span class="hljs-comment">// 通过 req.query 可以获取到客户端发送过来的 查询参数 ‘/’表示ip根目录</span><br>  <span class="hljs-comment">// 注意：默认情况下，req.query 是一个空对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(req.<span class="hljs-property">query</span>)<br>  res.<span class="hljs-title function_">send</span>(req.<span class="hljs-property">query</span>)<br>&#125;)<br><br><br><span class="hljs-comment">// 注意：这里的 :id 是一个动态的参数</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user/:id/:username&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// req.params 是动态匹配到的 URL 参数，默认也是一个空对象</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(req.<span class="hljs-property">params</span>)<br>  res.<span class="hljs-title function_">send</span>(req.<span class="hljs-property">params</span>)<br>&#125;)<br><br><span class="hljs-comment">// 3. 启动 web 服务器</span><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;express server running at http://127.0.0.1&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure>

<blockquote>
<p>:id 是一个动态的参数，‘：’是固定的写法，可以有多个参数，其中id 是该参数名字，而req.params可以动态匹配该参数的值。</p>
</blockquote>
<h3 id="托管静态资源"><a href="#托管静态资源" class="headerlink" title="托管静态资源"></a>托管静态资源</h3><ul>
<li>express.static()，可以非常方便地创建一个静态资源服务器，</li>
</ul>
<p>  例如，通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外开放访问了</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">app.<span class="hljs-title function_">use</span>(express.<span class="hljs-title function_">static</span>(<span class="hljs-string">&#x27;public&#x27;</span>))<br></code></pre></td></tr></table></figure>

<blockquote>
<p>注意：Express 在指定的静态目录中查找文件，对外提供资源访问路径，目录名不会出现在 URL 中</p>
</blockquote>
<h3 id="挂载路径前缀"><a href="#挂载路径前缀" class="headerlink" title="挂载路径前缀"></a>挂载路径前缀</h3><p>如果希望在托管的静态资源访问路径之前，挂载路径前缀，则可以使用如下的方式</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/public&#x27;</span>, express.<span class="hljs-title function_">static</span>(<span class="hljs-string">&#x27;public&#x27;</span>))<br></code></pre></td></tr></table></figure>

<h3 id="Express-路由"><a href="#Express-路由" class="headerlink" title="Express 路由"></a>Express 路由</h3><p>在 Express 中，路由指的是客户端的请求与服务器处理函数之间的映射关系</p>
<ul>
<li>Express 中的路由分 3 部分组成，分别是请求的类型、请求的 URL 地址、处理函数，格式如下</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">method</span>(path, <span class="hljs-title function_">handler</span>())	<span class="hljs-comment">// method 具体为 get post 等</span><br></code></pre></td></tr></table></figure>

<p>在 Express 中使用路由最简单的方式，就是把路由挂载到 app 上，示例代码：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">// 挂载路由</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;hello world.&#x27;</span>)&#125;)<br>app.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Post Request.&#x27;</span>)&#125;)<br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;express server running at http://127.0.0.1&#x27;</span>)&#125;)<br></code></pre></td></tr></table></figure>

<p><strong>模块化路由</strong></p>
<p>为了方便对路由进行模块化的管理，Express 不建议将路由直接挂载到 app 上，而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下</p>
<ul>
<li>创建路由模块对应的 .js 文件</li>
<li>调用 express.Router() 函数创建路由对象</li>
<li>向路由对象上挂载具体的路由</li>
<li>使用 module.exports 向外共享路由对象</li>
<li>使用 app.use() 函数注册路由模块</li>
</ul>
<p>新建router.js路由</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 路由模块 router.js</span><br><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)	<span class="hljs-comment">// 1. 导入 express</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()			<span class="hljs-comment">// 2. 创建路由对象</span><br><br><span class="hljs-comment">// 3. 挂载具体的路由</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user/list&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Get user list.&#x27;</span>)&#125;)<br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/user/add&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Add new user.&#x27;</span>)&#125;)<br><br><span class="hljs-comment">// 4. 向外导出路由对象 </span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./router&#x27;</span>)	<span class="hljs-comment">// 1. 导入路由模块</span><br><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/api&#x27;</span>, router)	<span class="hljs-comment">// 2. 注册路由模块，若想使用静态资源一样可以加统一的访问前缀</span><br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;http://127.0.0.1&#x27;</span>)&#125;)<br></code></pre></td></tr></table></figure>

<blockquote>
<p>app.use() 函数的作用，就是来注册全局中间件</p>
</blockquote>
<h3 id="Express-中间件"><a href="#Express-中间件" class="headerlink" title="Express 中间件"></a>Express 中间件</h3><p>格式</p>
<ul>
<li>Express 的中间件，本质上就是一个 <strong>function 处理函数</strong>，Express 中间件的格式如下</li>
<li>注意：中间件函数的形参列表中，必须包含 <strong>next 参数</strong>，而路由处理函数中只包含 req 和 res</li>
</ul>
<img src="" srcset="/blog/img/loading.gif" lazyload data-original="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/%20markdown/image-20230427221631354.png" alt="image-20230427221631354" style="zoom:80%;">

<ul>
<li><p>next 函数是实现多个中间件连续调用的关键，它表示把流转关系<strong>转交</strong>给下一个中间件或路由</p>
<p>全局生效的中间件：是客户端发起的任何请求，达到服务器之后，都会触发的中间件。</p>
</li>
</ul>
<blockquote>
<p>请求先到服务器——&gt;中间件——&gt;下一个中间件，没有就开始匹配路由。</p>
</blockquote>
<p>通过**app.use(中间件函数)**，定义全局中间件</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">//mw指向的就是一个中间件函数</span><br><span class="hljs-keyword">const</span> mw = <span class="hljs-keyword">function</span> (<span class="hljs-params">req, res, next</span>) &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;这是最简单的中间件函数&#x27;</span>)<br>  <span class="hljs-comment">// 把流转关系，转交给下一个中间件或路由</span><br>  <span class="hljs-title function_">next</span>()<br>&#125;<br><br><span class="hljs-comment">// 将 mw 注册为全局生效的中间件</span><br>app.<span class="hljs-title function_">use</span>(mw)<br><br><span class="hljs-comment">// 这是定义全局中间件的简化形式</span><br><span class="hljs-comment">// app.use((req, res, next) =&gt; &#123;</span><br><span class="hljs-comment">//   console.log(&#x27;这是最简单的中间件函数&#x27;)</span><br><span class="hljs-comment">//   next()</span><br><span class="hljs-comment">// &#125;)</span><br><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;调用了 / 这个路由&#x27;</span>)<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Home page.&#x27;</span>)<br>&#125;)<br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;http://127.0.0.1&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="http://127.0.0.1/%E8%AF%B7%E6%B1%82%E5%85%88%E5%88%B0mv%E4%B8%AD%E9%97%B4%E4%BB%B6%E5%A4%84%E7%90%86%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E5%88%B0%E4%B8%8B%E4%B8%80%E4%B8%AA%E4%B8%AD%E9%97%B4%E4%BB%B6%EF%BC%8C%E7%94%B1%E4%BA%8E%E6%B2%A1%E6%9C%89%E4%B8%8B%E4%B8%80%E4%B8%AA%E4%B8%AD%E9%97%B4%E4%BB%B6%EF%BC%8C%E5%B0%B1%E5%BC%80%E5%A7%8B%E5%8C%B9%E9%85%8D%E8%B7%AF%E7%94%B1%E3%80%82">http://127.0.0.1/请求先到mv中间件处理，然后再到下一个中间件，由于没有下一个中间件，就开始匹配路由。</a></p>
<p>中间件的作用</p>
<ul>
<li>多个中间件之间，共享同一份 req和 res。</li>
<li>基于这样的特性，我们可以在上游的中间件中，统一为 req 或 res 对象添加自定义的属性或方法，供下游的中间件或路由进行使用</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">//定义全局中间件的简化形式</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> &#123;<br>  <span class="hljs-keyword">const</span> time = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>()	<span class="hljs-comment">// 获取到请求到达服务器的时间</span><br>  req.<span class="hljs-property">startTime</span> = time	<br>    <span class="hljs-comment">// 为 req 对象，挂载自定义属性，从而把时间共享给后面的所有路由！！！！！！！！！！</span><br>  <span class="hljs-title function_">next</span>()<br>&#125;)<br><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Home page.&#x27;</span> + req.<span class="hljs-property">startTime</span>)&#125;)<br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;User page.&#x27;</span> + req.<span class="hljs-property">startTime</span>)&#125;)<br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;http://127.0.0.1&#x27;</span>)&#125;)<br></code></pre></td></tr></table></figure>

<p><strong>定义多个全局中间件</strong>，按照顺序先后调用</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">// 定义第一个全局中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;调用了第1个全局中间件&#x27;</span>)<br>  <span class="hljs-title function_">next</span>()<br>&#125;)<br><span class="hljs-comment">// 定义第二个全局中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;调用了第2个全局中间件&#x27;</span>)<br>  <span class="hljs-title function_">next</span>()<br>&#125;)<br><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;User page.&#x27;</span>)&#125;)<br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-function">() =&gt;</span> &#123;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;http://127.0.0.1&#x27;</span>)&#125;)<br></code></pre></td></tr></table></figure>

<p>局部生效的中间件<strong>：</strong>不使用 app.use() 定义的中间件叫做局部生效的中间件</p>
<p><strong>定义多个局部中间件</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">// 1. 定义中间件函数</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">mw1</span> = (<span class="hljs-params">req, res, next</span>) =&gt; &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;调用了局部生效的中间件&#x27;</span>)<br>  <span class="hljs-title function_">next</span>()<br>&#125;<br><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">mw2</span> = (<span class="hljs-params">req, res, next</span>) =&gt; &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;调用了第二个局部生效的中间件&#x27;</span>)<br>  <span class="hljs-title function_">next</span>()<br>&#125;<br><br><span class="hljs-comment">// 2. 创建路由，可见mw1，mw2只会在对应有调用的中间件中生效，调用：在get中的url和method中加一个/多个参数</span><br><span class="hljs-comment">//以下两种方式等价</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, mw1, nw2, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;Home page.&#x27;</span>)&#125;)<br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/user&#x27;</span>, [mw1, mw2],<span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;User page.&#x27;</span>)&#125;)<br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">80</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)&#125;)<br></code></pre></td></tr></table></figure>

<p>中间件的使用注意事项</p>
<ul>
<li>一定要在路由之前注册中间件，如果直接匹配到路由就会直接响应了</li>
<li>执行完中间件的业务代码之后，不要忘记调用**next() **函数</li>
<li>为了防止代码逻辑混乱，调用 next() 函数后不要再写额外的代码</li>
<li>连续调用多个中间件时，多个中间件之间，<strong>共享</strong>req 和 res 对象</li>
</ul>
<p><strong>中间件的分类</strong></p>
<ul>
<li><p>应用级别的中间件（绑定到app实例上）</p>
</li>
<li><p>路由级别的中间件（绑定到路由实例上）</p>
</li>
<li><p>错误级别的中间件</p>
<blockquote>
<p>格式：错误级别中间件的 <strong>function 处理函数中</strong>，必须有 4 个形参，形参<strong>顺序从前到后</strong>，分别是 **(err, req, res, next)**。</p>
<p>错误级别的中间件，必须注册在所有路由之后！</p>
</blockquote>
</li>
<li><p>Express 内置的中间件</p>
<ul>
<li><strong>express.static()</strong> 快速托管静态资源的内置中间件，例如： HTML 文件、图片、CSS 样式等（<strong>无兼容性，任何版本都能用</strong>）</li>
<li>**express.json() **解析 JSON 格式的请求体数据（有兼容性，仅在 4.16.0+ 版本中可用）</li>
<li>**express.urlencoded(option) **解析 URL-encoded 格式的请求体数据（有兼容性，仅在 4.16.0+ 版本中可用）</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br></code></pre></td></tr></table></figure></li>
</ul>
<h2 id="10-使用Express写接口"><a href="#10-使用Express写接口" class="headerlink" title="10.使用Express写接口"></a>10.使用Express写接口</h2><p>1.先创建一个Express服务器，使用express写接口.js</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express);	// 导入express</span><br><span class="hljs-string">                        </span><br><span class="hljs-string">const app = express();							// 创建服务器实例</span><br><span class="hljs-string"></span><br><span class="hljs-string">//写别的代码,导入路由模块之类的</span><br><span class="hljs-string"></span><br><span class="hljs-string">app.listen(80, () =&gt; &#123;							// 调用回调函数，listen() 启动服务器</span><br><span class="hljs-string">	console.log(&#x27;</span>express server running at <span class="hljs-attr">http</span>:<span class="hljs-comment">//127.0.0.1&#x27;)</span><br>&#125;);<br></code></pre></td></tr></table></figure>

<p>2.创建路由模块,apiRouter.js</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)	<span class="hljs-comment">// 1. 导入 express</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()			<span class="hljs-comment">// 2. 创建路由对象</span><br><br><span class="hljs-comment">// 4. 挂载具体的路由</span><br><br><span class="hljs-comment">// 3. 向外导出路由对象 </span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure>

<p>3.导入路由模块,在express写接口.js</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express);	// 导入express</span><br><span class="hljs-string">                        </span><br><span class="hljs-string">const app = express();							// 创建服务器实例</span><br><span class="hljs-string"></span><br><span class="hljs-string">//导入路由模块</span><br><span class="hljs-string">const router = require(&#x27;</span>./apiRouter<span class="hljs-string">&#x27;)</span><br><span class="hljs-string">//把路由模块。注册到app上</span><br><span class="hljs-string">app.use(&#x27;</span>/api<span class="hljs-string">&#x27;, router)	</span><br><span class="hljs-string"></span><br><span class="hljs-string"></span><br><span class="hljs-string">app.listen(80, () =&gt; &#123;							// 调用回调函数，listen() 启动服务器</span><br><span class="hljs-string">	console.log(&#x27;</span>express server running at <span class="hljs-attr">http</span>:<span class="hljs-comment">//127.0.0.1&#x27;)</span><br>&#125;);<br></code></pre></td></tr></table></figure>

<p>4.1 编写GET接口，在apiRouter.js</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)	<span class="hljs-comment">// 1. 导入 express</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()			<span class="hljs-comment">// 2. 创建路由对象</span><br><br><span class="hljs-comment">// 4. 挂载具体的路由</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/get&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 通过req.query获取客户端通过查询字符串，发送到服务器的数据</span><br>    <span class="hljs-keyword">const</span> query = req.<span class="hljs-property">query</span><br>    <span class="hljs-comment">// 调用res.send()方法，向客户端响应处理的结果</span><br>    res.<span class="hljs-title function_">send</span>(&#123;<br>        <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,         <span class="hljs-comment">//0表示处理成功，1表示处理失败</span><br>        <span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;GET请求成功！&#x27;</span>, <span class="hljs-comment">//状态描述</span><br>        <span class="hljs-attr">data</span>: query        <span class="hljs-comment">//需要响应给客户端的数据</span><br>    &#125;)<br>&#125;)<br><br><span class="hljs-comment">// 3. 向外导出路由对象 </span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure>

<p>4.2 编写POST接口，在apiRouter.js</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)	<span class="hljs-comment">// 1. 导入 express</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()			<span class="hljs-comment">// 2. 创建路由对象</span><br><br><span class="hljs-comment">// 4. 挂载具体的路由</span><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/get&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 通过req.query获取客户端通过查询字符串，发送到服务器的数据</span><br>    <span class="hljs-keyword">const</span> query = req.<span class="hljs-property">query</span><br>    <span class="hljs-comment">// 调用res.send()方法，向客户端响应处理的结果</span><br>    res.<span class="hljs-title function_">send</span>(&#123;<br>        <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,         <span class="hljs-comment">//0表示处理成功，1表示处理失败</span><br>        <span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;GET请求成功！&#x27;</span>, <span class="hljs-comment">//状态描述</span><br>        <span class="hljs-attr">data</span>: query        <span class="hljs-comment">//需要响应给客户端的数据</span><br>    &#125;)<br>&#125;)<br>app.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/post&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 通过req.body获取发送到服务器的URL-encoded数据</span><br>    <span class="hljs-keyword">const</span> body = req.<span class="hljs-property">body</span><br>    <span class="hljs-comment">// 调用res.send()方法，向客户端响应处理的结果</span><br>    res.<span class="hljs-title function_">send</span>(&#123;<br>        <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,         <span class="hljs-comment">//0表示处理成功，1表示处理失败</span><br>        <span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;GET请求成功！&#x27;</span>, <span class="hljs-comment">//状态描述</span><br>        <span class="hljs-attr">data</span>: body        <span class="hljs-comment">//需要响应给客户端的数据</span><br>    &#125;)<br>&#125;)<br><span class="hljs-comment">// 3. 向外导出路由对象 </span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure>

<blockquote>
<p>注意: 如果要获取URL-encoded格式的请求体数据，必须配置中间件app.use(express.urlencoded({ extended: false ))，在express写接口.js中</p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express);	// 导入express</span><br><span class="hljs-string">                        </span><br><span class="hljs-string">const app = express();							// 创建服务器实例</span><br><span class="hljs-string"></span><br><span class="hljs-string">//配置解析表单数据的中间件</span><br><span class="hljs-string">app.use(express.urlencoded(&#123; extended: false )) </span><br><span class="hljs-string">//导入路由模块</span><br><span class="hljs-string">const router = require(&#x27;</span>./apiRouter<span class="hljs-string">&#x27;)</span><br><span class="hljs-string">//把路由模块。注册到app上</span><br><span class="hljs-string">app.use(&#x27;</span>/api<span class="hljs-string">&#x27;, router)	</span><br><span class="hljs-string"></span><br><span class="hljs-string"></span><br><span class="hljs-string">app.listen(80, () =&gt; &#123;							// 调用回调函数，listen() 启动服务器</span><br><span class="hljs-string">	console.log(&#x27;</span>express server running at <span class="hljs-attr">http</span>:<span class="hljs-comment">//127.0.0.1&#x27;)</span><br>&#125;);<br></code></pre></td></tr></table></figure>

<h3 id="CORS-跨域资源共享"><a href="#CORS-跨域资源共享" class="headerlink" title="CORS 跨域资源共享"></a>CORS 跨域资源共享</h3><p>刚才编写的 GET 和 POST接口，存在一个很严重的问题：不支持跨域请求，解决接口跨域问题的方案主要有两种</p>
<ul>
<li>CORS（主流解决方案，推荐）</li>
<li>JSONP（有缺陷：只支持 GET 请求）</li>
</ul>
<p>使用 CORS 中间件解决跨域问题，步骤分为如下 3 步</p>
<ul>
<li>运行 <code>npm install cors </code>安装中间件</li>
<li>使用 <code>const cors = require(‘cors’) </code>导入中间件</li>
<li>在路由之前调用 <code>app.use(cors()) </code>配置中间件</li>
</ul>
<blockquote>
<p>要在所有路由之前，配置cors中间件</p>
</blockquote>
<h2 id="11-Express项目操作数据库"><a href="#11-Express项目操作数据库" class="headerlink" title="11.Express项目操作数据库"></a>11.Express项目操作数据库</h2><p>步骤：</p>
<ol>
<li><p>安装操作MySQL数据库的第三方模块（mysql）</p>
<figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cmd">npm install mysql<br></code></pre></td></tr></table></figure>
</li>
<li><p>通过mysql模块连接到MySQL数据库</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">//1. 导入myql模块</span><br><span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;mysql&#x27;</span>)<br><span class="hljs-comment">//2. 建立于MySQL数据库的连接</span><br><span class="hljs-keyword">const</span> db = mysql.<span class="hljs-title function_">createPool</span>(&#123;<br>    <span class="hljs-attr">host</span>: <span class="hljs-string">&#x27;127.0.0.1&#x27;</span>,<br>    <span class="hljs-attr">user</span>: <span class="hljs-string">&#x27;root&#x27;</span>,<br>    <span class="hljs-attr">password</span>: <span class="hljs-string">&#x27;123456&#x27;</span>,<br>    <span class="hljs-attr">database</span>: <span class="hljs-string">&#x27;my_db_01&#x27;</span><br>&#125;)<br></code></pre></td></tr></table></figure>
</li>
<li><p>通过mysql模块执行SQL语句</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">//1. 导入myql模块</span><br><span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;mysql&#x27;</span>)<br><span class="hljs-comment">//2. 建立于MySQL数据库的连接</span><br><span class="hljs-keyword">const</span> db = mysql.<span class="hljs-title function_">createPool</span>(&#123;<br>    <span class="hljs-attr">host</span>: <span class="hljs-string">&#x27;127.0.0.1&#x27;</span>,<br>    <span class="hljs-attr">user</span>: <span class="hljs-string">&#x27;root&#x27;</span>,<br>    <span class="hljs-attr">password</span>: <span class="hljs-string">&#x27;123456&#x27;</span>,<br>    <span class="hljs-attr">database</span>: <span class="hljs-string">&#x27;my_db_01&#x27;</span><br>&#125;)<br><span class="hljs-comment">//3. 测试mysql模块能否正常工作</span><br>db.<span class="hljs-title function_">query</span>(<span class="hljs-string">&#x27;select 1&#x27;</span>,<span class="hljs-function">(<span class="hljs-params">err,results</span>)=&gt;</span>&#123;<br>    <span class="hljs-keyword">if</span>(err) <span class="hljs-keyword">return</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(err.<span class="hljs-property">message</span>)<br>    <br>    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(results)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p> 查询</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sqlStr = <span class="hljs-string">&#x27;select * FROM users&#x27;</span><br>db.<span class="hljs-title function_">query</span>(sqlStr,<span class="hljs-function">(<span class="hljs-params">err,results</span>)=&gt;</span>&#123;<br>    <span class="hljs-keyword">if</span>(err) <span class="hljs-keyword">return</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(err.<span class="hljs-property">message</span>)<br>    <br>    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(results)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h2 id="12-身份认证"><a href="#12-身份认证" class="headerlink" title="12.身份认证"></a>12.身份认证</h2><p>不同开发模式下的身份认证</p>
<ul>
<li>服务端渲染推荐使用Session认证机制</li>
<li>前后端分离推荐使用 JWT认证机制</li>
</ul>
<h3 id="Session认证机制"><a href="#Session认证机制" class="headerlink" title="Session认证机制"></a>Session认证机制</h3><p>由于HTTP协议的无状态性，服务器不会主动保留每次HTTP请求的状态。会话（Session）跟踪是Web程序中常用的技术，用来<strong>跟踪用户的整个会话</strong>，最主要的目的是<strong>帮助服务器记住客户端状态</strong>（标识用户，跟踪状态）。</p>
<p>常用的会话跟踪技术是<code>Cookie</code>与<code>Session</code>。<strong>Cookie通过在客户端记录信息确定用户身份，Session通过在服务器端记录信息确定用户身份。</strong></p>
<h4 id="Cookie"><a href="#Cookie" class="headerlink" title="Cookie"></a>Cookie</h4><p><strong>Cookie</strong>类比于会员卡。比如生活中的超市，付钱买东西操作。服务员不会记得你是不是会员，除非你有会员卡。</p>
<p>Cookie是存储在用户浏览器中的一段不超过4 KB的字符串。它由一个名称(Name)、一个值(Value) 和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。特性：</p>
<ul>
<li>自动发送</li>
<li>域名独立</li>
<li>过期时限</li>
<li>4KB限制</li>
</ul>
<p><img src="" srcset="/blog/img/loading.gif" lazyload data-original="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/%20markdown/image-20230427221713313.png" alt="image-20230427221713313"></p>
<p>由于Cookie是存储在浏览器中的，而且浏览器也提供了读写Cookie的API,因此<strong>Cookie很容易被伪造</strong>,不具有安全性。因此不建议服务器将重要的隐私数据，</p>
<p>通过Cookie的形式发送给浏览器。</p>
<p>为了解决安全性问题，服务器根据请求中携带的Cookie要从内存中查找对应的用户信息。这样除了客户端用到Cookie，服务端也用到session确认用户身份。</p>
<p><strong>Cookie通过在客户端记录信息确定用户身份，Session通过在服务器端记录信息确定用户身份</strong>。</p>
<h4 id="Session"><a href="#Session" class="headerlink" title="Session"></a>Session</h4><p>Express使用Session认证：</p>
<ol>
<li>安装express-session中间件</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">npm install express-session<br></code></pre></td></tr></table></figure>

<ol start="2">
<li>配置express-session中间件</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 1.导入session 中间件</span><br><span class="hljs-keyword">var</span> session = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express-session&#x27;</span> )<br><br><span class="hljs-comment">// 2.配置Seesion中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-title function_">session</span>(&#123;<br>    <span class="hljs-attr">secret</span>:<span class="hljs-string">&#x27;keyboard cat&#x27;</span>, <span class="hljs-comment">// secret属性的值可以为任意字符串</span><br>    <span class="hljs-attr">resave</span>:<span class="hljs-literal">false</span>,<br>    <span class="hljs-attr">saveUninitialized</span>:<span class="hljs-literal">true</span><br>&#125;))<br></code></pre></td></tr></table></figure>

<ol start="3">
<li>向session中存数据</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/api/login&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 判断用户提交的登录信息是否正确</span><br>    <span class="hljs-keyword">if</span>(req.<span class="hljs-property">body</span>.<span class="hljs-property">username</span> !==<span class="hljs-string">&#x27;admin&#x27;</span>|| req.<span class="hljs-property">body</span>.<span class="hljs-property">password</span>!=<span class="hljs-string">&#x27;000000&#x27;</span>)&#123;<br>        <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123;<span class="hljs-attr">status</span>:<span class="hljs-number">1</span>,<span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;登录失败&#x27;</span>&#125;)<br>    &#125;<br>    req.<span class="hljs-property">session</span>.<span class="hljs-property">userinfo</span> = req.<span class="hljs-property">body</span> <span class="hljs-comment">//将用户信息保存到Session中</span><br>    req.<span class="hljs-property">session</span>.<span class="hljs-property">islogin</span> = <span class="hljs-literal">true</span> <span class="hljs-comment">//将用户登录状态，存储到Session中</span><br>    <br>    res.<span class="hljs-title function_">send</span>(&#123;<span class="hljs-attr">status</span>:<span class="hljs-number">0</span>,<span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;登录成功&#x27;</span>&#125;)<br>&#125;)<br></code></pre></td></tr></table></figure>

<ol start="4">
<li>从session中取数据</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/api/username&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 判断用户是否登录</span><br>    <span class="hljs-keyword">if</span>(！req.<span class="hljs-property">session</span>.<span class="hljs-property">islogin</span>)&#123;<br>        <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123;<span class="hljs-attr">status</span>:<span class="hljs-number">1</span>,<span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;fail&#x27;</span>&#125;)<br>    &#125;<br>       <br>    res.<span class="hljs-title function_">send</span>(&#123;<span class="hljs-attr">status</span>:<span class="hljs-number">0</span>,<span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;success&#x27;</span>,<span class="hljs-attr">username</span>:req.<span class="hljs-property">session</span>.<span class="hljs-property">user</span>.<span class="hljs-property">username</span>&#125;)<br>&#125;)<br></code></pre></td></tr></table></figure>

<p>5.清空当前用户的session</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">req.<span class="hljs-property">session</span>.<span class="hljs-title function_">destory</span>()<br></code></pre></td></tr></table></figure>

<p>Session认证机制需要配合Cookie才能实现。由于Cookie默认不支持跨域访问,所以，当涉及到前端跨域请求后端接口的时候，需要做很多额外的配置，才能实现跨域Session认证。</p>
<h3 id="JWT认证机制"><a href="#JWT认证机制" class="headerlink" title="JWT认证机制"></a>JWT认证机制</h3><p><img src="" srcset="/blog/img/loading.gif" lazyload data-original="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/%20markdown/image-20230427221734114.png" alt="image-20230427221734114"></p>
<p>组成</p>
<p>JWT通常由三部分组成，分别是Header (头部)、Payload (有效荷载)、Signature (签名)。</p>
<p>三者之间使用英文的”.” 分隔，其中</p>
<ul>
<li>Payload 部分才是真正的用户信息，它是用户信息经过加密之后生成的字符串。</li>
<li>Header 和Signature是安全性相关的部分，只是为了保证Token的安全性。</li>
</ul>
<p>流程：</p>
<ul>
<li><p>客户端收到服务器返回的JWT之后，通常会将它储存在localStorage或sessionStorage中。</p>
</li>
<li><p>此后，客户端每次与服务器通信，都要带上这个JWT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中，格式如下:</p>
</li>
</ul>
<blockquote>
<p>Authorization: Bearer <token></token></p>
</blockquote>
<h4 id="Express使用-JWT认证"><a href="#Express使用-JWT认证" class="headerlink" title="Express使用 JWT认证"></a>Express使用 JWT认证</h4><ol>
<li>安装JWT相关的包</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">npm install jsonwebtoken express-jwt<br></code></pre></td></tr></table></figure>

<p>其中:</p>
<ul>
<li>jsonwebtoken 用于生成JWT字符串</li>
<li>express-jwt 用于将JWT字符串解析还原成JSON对象</li>
</ul>
<ol start="2">
<li>导入JWT相关的包</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 1.导入用于生产 JWT 字符串的包</span><br><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;jsonwebtoken&#x27;</span> )<br><span class="hljs-comment">// 2.导入用于将客户端发送过来的JWT字符串，解析还原成JSON 对象的包</span><br><span class="hljs-keyword">const</span> expressJWT = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express-jwt&#x27;</span>)<br></code></pre></td></tr></table></figure>

<ol start="3">
<li>定义secret密钥<br>①当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密，最终得到加密好的JWT字符串<br>②当把JWT字符串解析还原成JSON对象的时候，需要使用secret密钥进行解密</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> secretKey = <span class="hljs-string">&#x27;suibian&#x27;</span><br></code></pre></td></tr></table></figure>

<ol start="4">
<li>在登录成功后生成JWT字符串</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/api/login&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 判断用户提交的登录信息是否正确</span><br>    <span class="hljs-keyword">if</span>(req.<span class="hljs-property">body</span>.<span class="hljs-property">username</span> !==<span class="hljs-string">&#x27;admin&#x27;</span>|| req.<span class="hljs-property">body</span>.<span class="hljs-property">password</span>!=<span class="hljs-string">&#x27;000000&#x27;</span>)&#123;<br>        <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123;<span class="hljs-attr">status</span>:<span class="hljs-number">1</span>,<span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;登录失败&#x27;</span>&#125;)<br>    &#125;<br>    res.<span class="hljs-title function_">send</span>(&#123;<br>        <span class="hljs-attr">status</span>:<span class="hljs-number">0</span>,<br>        <span class="hljs-attr">msg</span>:<span class="hljs-string">&#x27;登录成功&#x27;</span>,<br>        <span class="hljs-comment">//调用jwt,sign() 生成JWT字符串，三个参数分别是:用户信息对象、加密密钥、配置对象</span><br>        <span class="hljs-attr">token</span>: jwt.<span class="hljs-title function_">sign</span>(&#123; <span class="hljs-attr">username</span>: user info.<span class="hljs-property">username</span> &#125;，secretKey, &#123; <span class="hljs-attr">expiresIn</span>:<span class="hljs-string">&#x27; 30s&#x27;</span><br>    &#125;)<br>&#125;)<br></code></pre></td></tr></table></figure>

<ol start="5">
<li>将JWT字符串还原为JSON对象</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> secretKey = <span class="hljs-string">&#x27;suibian&#x27;</span><br><span class="hljs-comment">// .unless(&#123; path: [/^\/api\//] &#125;)//指定哪些接口不需要访问权限</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-title function_">expressJWT</span>(&#123; <span class="hljs-attr">secret</span>: secretKey &#125;).<span class="hljs-title function_">unless</span>(&#123; <span class="hljs-attr">path</span>: [<span class="hljs-regexp">/^\/api\//</span>] &#125;))<br></code></pre></td></tr></table></figure>

<ol start="6">
<li>使用req.user获取用户信息</li>
</ol>
<blockquote>
<p>req.user中的信息时加密时封的用户信息</p>
</blockquote>
<ol start="7">
<li>捕获解析JWT失败后产生的错误</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs javascript">app.<span class="hljs-title function_">use</span>(<span class="hljs-function">(<span class="hljs-params">err,req,res,next</span>)=&gt;</span>&#123;<br>    <span class="hljs-comment">//token解析失败导致的错误</span><br>    <span class="hljs-keyword">if</span>(err.<span class="hljs-property">name</span> === <span class="hljs-string">&#x27;UnauthorizedError&#x27;</span>)&#123;<br>        <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123;<br>            <span class="hljs-attr">status</span>:<span class="hljs-number">401</span>,<br>            <span class="hljs-attr">messaage</span>:<span class="hljs-string">&#x27;无效的token&#x27;</span><br>        &#125;)<br>        <span class="hljs-comment">// 其他原因导致的错误</span><br>        res.<span class="hljs-title function_">send</span>(&#123;<br>            <span class="hljs-attr">status</span>:<span class="hljs-number">500</span>,<br>            <span class="hljs-attr">message</span>:<span class="hljs-string">&#x27;未知错误&#x27;</span><br>        &#125;)<br>    &#125;<br>&#125;)<br></code></pre></td></tr></table></figure>

<p>实战项目：<a target="_blank" rel="noopener" href="http://www.escook.cn:8088/#/">http://www.escook.cn:8088/#/</a></p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/blog/categories/%E5%90%8E%E7%AB%AF%E6%8A%80%E6%9C%AF%E6%A0%88/" class="category-chain-item">后端技术栈</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/blog/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/">#服务器</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>Node.js</div>
      <div>https://airfe.gitee.io/blog/2023/04/01/Node.js/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>Airfe</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2023年4月1日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/blog/2023/04/01/MongoDB/" title="MongoDB">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">MongoDB</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/blog/2023/03/25/Sass%E8%AF%AD%E6%B3%95%E8%A7%84%E5%88%99/" title="Sass语法规则">
                        <span class="hidden-mobile">Sass语法规则</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
  
  
    <article id="comments" lazyload>
      
  <div id="valine"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#valine', function() {
      Fluid.utils.createScript('https://lib.baomitu.com/valine/1.5.1/Valine.min.js', function() {
        var options = Object.assign(
          {"appId":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","appKey":"P5fzMTGSJIoTaGvmgzsUHeNZ","path":"window.location.pathname","placeholder":"发表你的看法吧~","avatar":"retro","meta":["nick","mail","link"],"requiredFields":[],"pageSize":10,"lang":"zh-CN","highlight":false,"recordIP":false,"serverURLs":"","emojiCDN":null,"emojiMaps":null,"enableQQ":false,"appid":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","appkey":"P5fzMTGSJIoTaGvmgzsUHeNZ","server_url":"https://rw68dmke.lc-cn-n1-shared.com"},
          {
            el: "#valine",
            path: window.location.pathname
          }
        )
        new Valine(options);
        Fluid.utils.waitElementVisible('#valine .vcontent', () => {
          var imgSelector = '#valine .vcontent img:not(.vemoji)';
          Fluid.plugins.imageCaption(imgSelector);
          Fluid.plugins.fancyBox(imgSelector);
        })
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


    </article>
  


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
        <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> <div style="font-size: 0.85rem"> <span id="timeDate">载入天数</span> <span id="times">载入时分秒</span> <script src="js/duration.js"></script> </div> 
    </div>
  
  
    <div class="statistics">
  
  

  
    
      <span id="leancloud-site-pv-container" style="display: none">
        总访问量 
        <span id="leancloud-site-pv"></span>
         次
      </span>
    
    
      <span id="leancloud-site-uv-container" style="display: none">
        总访客数 
        <span id="leancloud-site-uv"></span>
         人
      </span>
    
    

  
</div>

  
  
    <!-- 备案信息 ICP for China -->
    <div class="beian">
  <span>
    <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">
      蜀ICP备2023008943号
    </a>
  </span>
  
    
      <span>
        <a
          href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=https://beian.miit.gov.cn/"
          rel="nofollow noopener"
          class="beian-police"
          target="_blank"
        >
          
            <span style="visibility: hidden; width: 0">|</span>
            <img src="" srcset="/blog/img/loading.gif" lazyload data-original="/blog/img/police_beian.png" alt="police-icon"/>
          
          <span>京公网安备12345678号</span>
        </a>
      </span>
    
  
</div>

  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/blog/js/events.js" ></script>
<script  src="/blog/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/blog/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script defer src="/blog/js/leancloud.js" ></script>

  <script  src="/blog/js/local-search.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/blog/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>

        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(r){r.imageLazyLoadSetting.processImages=t;var e=r.imageLazyLoadSetting.isSPA,n=r.imageLazyLoadSetting.preloadRatio||1,c=a();function a(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){e&&(c=a());for(var t,o=0;o<c.length;o++)0<=(t=(t=c[o]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(r.innerHeight*n||document.documentElement.clientHeight*n)&&function(){var t,e,n,a,i=c[o];e=function(){c=c.filter(function(t){return i!==t}),r.imageLazyLoadSetting.onImageLoaded&&r.imageLazyLoadSetting.onImageLoaded(i)},(t=i).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,a=t.getAttribute("data-original"),n.onload=function(){t.src=a,t.removeAttribute("data-original"),e&&e()},t.src!==a&&(n.src=a))}()}function i(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",i),r.addEventListener("resize",i),r.addEventListener("orientationchange",i)}(this);</script></body>
</html>
